import { base64ToPathFn, downloadFile, showLoading, hideLoading, 
	countTextLength, getImageInfo, getModeImage, compressImage, getRpxOrUpxCompany, pxToRpx } from './util'

import QRCodeAlg from './qrcode'

const TYPES = ['2d', 'webgl']
export default class Draw{
	constructor(params = {}, callBackData = {
		endback: () => {},
		updatestyleback: () => {},
		updatecanvasback: () => {},
	}) {
		let { width, company, canvasId, type, height, background, drawDelayTime, delayTime, _this, fileType, quality, isCompressImage, success } = params
		this.company = company || 'px'
		this.width = this.getCompany(width)
		this.height = this.getCompany(height)
		this.canvasId = canvasId || null
		this.background = background || {
			type: 'color',
			w: width,
			h: height,
			color: '#ffffff'
		}
		this.drawDelayTime = drawDelayTime || 200
		this.delayTime = delayTime || 200
		this._this = _this || null
		// 导出图片的类型
		this.fileType = fileType || 'png'
		// 导出图片的质量
		this.quality = quality || 1
		// 是否压缩图片，填写时绘制图片会进行压缩操作。绘制图片也能填写该参数。层级大于当前
		this.isCompressImage = isCompressImage || false
		this.callBack = {
			bgObj: {
				width: this.background.w,
				height: this.background.h
			},
			ctxObj: {
				width,
				height
			},
			style: {
				width: this.getCompany(width) + 'px',
				height: this.getCompany(height) + 'px'
			}
		}
		this.drawTipsText = params.drawTipsText || '绘制中...'
		this.allCallBack = []
		this.type = type || ''
		this.success = success
		this.drawArray = () => {}
		this.callBackData = callBackData
		this.isUpdate = false
		this.getContext()
	}

	// 获取绘制对象
	getContext() {
		let { canvasId, _this, width, height, type, success } = this
		if (TYPES.includes(type)) {
			const query = uni.createSelectorQuery().in(_this)
			query.select(`#${canvasId}`)
			.fields({ node: true, size: true })
			.exec(res => {
				const canvas = res[0].node
				this.Context = canvas.getContext(type)
				const dpr = uni.getSystemInfoSync().pixelRatio
				canvas.width = width * dpr
				canvas.height = height * dpr
				this.canvas = canvas
				this.Context.scale(dpr, dpr)
				if (success != undefined && typeof success === 'function') {
					success()
				}
			})
		} else {
			this.Context = uni.createCanvasContext(canvasId, _this)
		}
	}

	/**
	 * 获取转换的单位
	 * @param { Number } size 尺寸大小
	 * @returns 
	 */
	getCompany(size) {
		const { company } = this
		if (typeof size === 'undefined' || typeof size === 'null') {
			return undefined
		}
		if(company == 'px') {
			return size
		}
		if (typeof size === 'number') {
			return uni.upx2px(size)
		}
		if (typeof size === 'string') {
			return getRpxOrUpxCompany(size)
		}
	}

	/**
	 * px转rpx
	 * @param {*} size 
	 * @returns 
	 */
	pxToRpx(size) {
		let { company } = this
		if(company == 'px') {
			return size
		}
		return size / (uni.upx2px(100) / 100)
	}

	/**
	 * 获取图片src路径
	 * @param { String } src 图片地址
	 * @returns 
	 */
	getImageSrc(src) {
		return new Promise(async resolve => {
			src = await base64ToPathFn(src)
			// #ifndef MP-TOUTIAO
			if (src.includes('http')) {
				let downlaod = await downloadFile(src)
				if (downlaod.data.statusCode != 200) {
					hideLoading()
					return resolve({
						success: false,
						msg: `图片路径为:${src}的文件下载失败`
					})
				}
				if (!downlaod.success) {
					hideLoading()
					return resolve({
						success: false,
						msg: '下载图片失败'
					})
				}
				src = downlaod.data.tempFilePath
			}
			// #endif
			return resolve({
				success: true,
				src
			})
		})
	}

	/**
	 * 设置透明度
	 * @param { number } alpha 透明度
	 */
	setAlpha(alpha = 1) {
		let { Context, type } = this
		if (TYPES.includes(type)) {
			Context.globalAlpha = alpha
		} else {
			Context.setGlobalAlpha(alpha)
		}
	}

	/**
	 * 设置填充颜色
	 * @param { String } style 填充颜色
	 */
	setFillStyle(style) {
		let { Context, type } = this
		if (TYPES.includes(type)) {
			Context.fillStyle = style
		} else {
			Context.setFillStyle(style)
		}
	}

	/**
	 * 设置宽度大小
	 * @param { number } width 宽度
	 */
	setLineWidth(width) {
		let { Context, type } = this
		if (TYPES.includes(type)) {
			Context.lineWidth = this.getCompany(width)
		} else {
			Context.setLineWidth(this.getCompany(width))
		}
	}

	/**
	 * 设置描边颜色
	 * @param { String } style 颜色
	 */
	setStrokeStyle(style) {
		let { Context, type } = this
		if (TYPES.includes(type)) {
			Context.strokeStyle = style
		} else {
			Context.setStrokeStyle(style)
		}
	}

	/**
	 * 获取阴影参数
	 * @param { Boolean } shadow.show 是否使用阴影
	 * @param { Number } shadow.x 阴影相对于形状在水平方向的偏移
	 * @param { Number } shadow.y 阴影相对于形状在竖直方向的偏移
	 * @param { Number } shadow.blur 阴影的模糊级别，数值越大越模糊
	 * @param { String } shadow.color 阴影的颜色
	 * @returns 
	 */
	getShadow(shadow = {}) {
		let { show, x, y, blur, color } = shadow
		return {
			show: show == undefined ? false : show,
			x: Number(this.getCompany(x)) || 0,
			y: Number(this.getCompany(y)) || 0,
			blur: blur || 0,
			color: color || '#000000'
		}
	}

	/**
	 * 获取绘制图片的内容
	 * @param { String } src 资源目录
	 */
	getImage(src) {
		let { type, canvas } = this
		if (TYPES.includes(type)) {
			const img = canvas.createImage()
			const imageData = canvas.createImageData()
			img.src = src
			return img
		} else {
			return src
		}
	}


	/**
	 * 获取绘制参数
	 * @param {*} params 
	 * @param { String } type 参数类别
	 */
	getDrawParams(params, type) {
		const { width } = this
		const { x, y, w, h, r, color, alpha, isFill, 
			lineWidth, windowAlign, rotate, drawImage, borderColor, 
			borderWidth, borderType, shadow, gradient,
		} = params
		let drawParams = {}
		if (type != 'image') {
			drawParams = {
				x: this.getCompany(x) || 0,
				y: this.getCompany(y) || 0,
				w: this.getCompany(w) || width,
				h: this.getCompany(h) || 0,
				r: this.getCompany(r) || 0,
			}
		} else {
			drawParams = {
				x: x || 0,
				y: y || 0,
				w: w || width,
				h: h || 0,
				r: r || 0,
			}
		}
		// 公共的参数
		const globalData = {
			...drawParams,
			color: color || '#000000',
			lineWidth: lineWidth || 2,
			borderWidth: borderWidth || 0,
			borderColor: borderColor || '#000000',
			borderType: borderType || 'default',
			alpha: alpha || 1,
			isFill: isFill == undefined ? true : isFill,
			// 窗口对齐的方式 默认: none 可选 居中: center 右边: right
			windowAlign: windowAlign || 'none',
			// 旋转
			rotate: rotate || {},
			// 阴影
			shadow: this.getShadow(shadow),
			// 渐变
			gradient: gradient || {},
		}
		// 绘制圆的参数
		const { s, e, d } = params
		const arcParams = {
			s: s || 0,
			e: e || Math.PI * 2,
			d: d == undefined ? false : d,
			// 是否是在绘制图片,默认不是
			drawImage: drawImage == undefined ? false : drawImage,
		}
		// 绘制三角形的参数
		const { coordinate, drawType, direction } = params
		const triangleParams = {
			// 当绘制类别是自定义的时候需要传递的参数
			coordinate: coordinate || [],
			// 绘制三角形的类型
			// right: 直角三角形
			// isosceles: 等腰三角形
			// custom: 自定义时，x, y, 宽, 高都不需要传递。需要传递绘制点的坐标类型是数组(coordinate)
			// [[1, 3], [2, 3], [4, 5]]
			drawType: drawType || 'isosceles',
			// 三角形顶点朝向 top, left, right, bottom
			direction: direction || 'top',
		}
		// 绘制图片的参数
		const { src, mode, triangle, isCompressImage, quality, drawSrc, drawModeImage, drawImageInfo } = params
		const imageParams = {
			src: src || '',
			mode: mode || 'aspectFill',
			drawType: drawType || 'default',
			// 绘制三角形图片时三角形的内容
			// triangle.type 三角形的类型 right: 直角三角形 isosceles: 等腰三角形 custom: 自定义三角形(不支持旋转)
			// triangle.coordinate 自定义三角形时传递的坐标
			// triangle.direction 三角形顶点朝向
			triangle: triangle || {},
			// 是否压缩图片
			isCompressImage: isCompressImage != undefined ? isCompressImage : this.isCompressImage,
			// 压缩图片时图片的质量只对jpg类型的图片生效
			quality:quality || 100,
			shadow: this.getShadow(shadow),
			drawSrc: drawSrc || false,
			drawModeImage: drawModeImage || false,
			drawImageInfo: drawImageInfo || false
		}
		// 绘制文字的参数
		const { text, textIndent, lastWidth, font, textAlign, baseline, line, highlightText, textRect } = params
		const textParams = {
			text: String(text) || '',
			textIndent: this.getCompany(textIndent) || 0,
			lastWidth: lastWidth || 0,
			font: this.getFont(font),
			textAlign: textAlign || 'none',
			baseline: baseline || 'top',
			line: this.getTextLine(line),
			highlightText: highlightText || [],
			textRect: textRect || { show: false, isFill: true, lineWidth: 1 },
			h
		}
		// 绘制线的参数
		const { algin, lineType, pattern, offset, lineCap } = params
		const lineParams = {
			algin: algin || 'right',
			// dashed 虚线 solid 实线
			lineType: lineType || 'solid',
			// 详看CanvasContext.setLineDash文档
			// 一组描述交替绘制线段和间距（坐标空间单位）长度的数字
			pattern: pattern || [this.getCompany(6), this.getCompany(6)],
			// 虚线偏移量
			offset: this.getCompany(offset) || this.getCompany(6),
			lineCap: lineCap || 'butt',
		}
		// 绘制二维码的参数
		const { image, size, lv, background, foreground, pdground } = params
		const qrCodeParams = {
			text,
			image: image || {},
			size: this.getCompany(size) || 100,
			// 容错级别 默认3
			correctLevel: lv || 3,
			// 二维码背景色
			background: background || '#ffffff',
			// 二维码前景色
			foreground: foreground || '#000000',
			// 二维码角标色
			pdground: pdground || '#000000',
		}
		switch(type) {
			// 矩形
			case 'rect':
				return globalData
			// 圆形
			case 'arc':
				return { ...globalData, ...arcParams}
			// 三角形
			case 'triangle':
				return { ...globalData, ...triangleParams }
			// 图片
			case 'image':
				return { ...globalData, ...imageParams }
			// 文字
			case 'text':
				return { ...globalData, ...textParams }
			// 线
			case 'line':
				return { ...globalData, ...lineParams }
			// 二维码
			case 'qrcode':
				return { ...globalData, ...qrCodeParams }
			default:
				return globalData
		}
	}

	/**
	 * 绘制图片内容
	 * @returns 
	 */
	drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh, x, y, w, h) {
		let { Context } = this
		// dx = this.getCompany(dx)
		// dy = this.getCompany(dy)
		// dw = this.getCompany(dw)
		// dh = this.getCompany(dh)
		sx = this.getCompany(sx)
		sy = this.getCompany(sy)
		sw = this.getCompany(sw)
		sh = this.getCompany(sh)
		// console.log({
		// 	dx, dy, dw, dh, sx, sy, sw, sh
		// })
		return new Promise(async resolve => {
			if (drawType == 'default') {
				await Context.drawImage(img, this.getCompany(x), this.getCompany(y), this.getCompany(w), this.getCompany(h))
			} else if (mode != 'default') {
				await Context.drawImage(img, dx, dy, dw, dh, sx, sy, sw, sh)
			} else {
				await Context.drawImage(img, dx, dy, dw, dh)
			}
			resolve(true)
		})
	}

	/**
	 * 据类型绘制图片
	 * @param {*} params 
	 * @returns 
	 */
	drawImageByType(params) {
		let { 
			imageInfo, r, x, y, w, h, rotate,
			borderWidth, borderColor, color, alpha, borderType, triangle, 
			mode, drawType, img, shadow, drawSrc, drawModeImage
		} = params
		let { Context } = this
		return new Promise(async resolve => {
			// hideLoading()
			// if (this.company == 'rpx') {
			// 	w = this.getCompany(w)
			// 	h = this.getCompany(h)
			// }
			if (h == 0) {
				h = w
			}
			// if ()
			let modeImage = drawModeImage
			if (!modeImage) {
				modeImage = getModeImage(Number(imageInfo.width), Number(imageInfo.height), x, y, w, h, mode)
			}
			let { dx, dy, dw, dh, sw, sh, sx, sy } = modeImage
			Context.save()
			Context.beginPath()
			if (drawType == 'default') {
				this.setRotate(this.getCompany(x), this.getCompany(y), this.getCompany(w), this.getCompany(h), rotate)
				// this.drawRect({
				// 	x,
				// 	y,
				// 	w,
				// 	h,
				// 	alpha,
				// 	color,
				// 	drawImage: true
				// })
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh, x, y, w, h)
				Context.clip()
				Context.restore()
			} else if (drawType == 'arc') {
				// 绘制圆形图片
				this.setRotate(this.getCompany(x), this.getCompany(y), this.getCompany(w), this.getCompany(h), rotate)
				this.drawArc({
					x,
					y,
					r: w / 2,
					borderWidth,
					borderColor,
					color,
					drawImage: true,
					shadow
				}, true)
				Context.clip()
				this.setAlpha(alpha)
				// console.log({
				// 	mode, img, dx, dy, dw, dh, sx, sy, sw, sh
				// })
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			} else if (drawType == 'rect') {
				// 绘制矩形图片
				this.setRotate(this.getCompany(x), this.getCompany(y), this.getCompany(w), this.getCompany(h), rotate)
				if (mode == 'widthFix') {
					h = sh
				}
				if (mode == 'heightFix') {
					w = sw
				}
				this.drawRect({
					x,
					y,
					w,
					h,
					alpha,
					borderWidth,
					borderColor,
					borderType,
					r,
					color,
					drawImage: true,
					shadow
				}, true)
				Context.clip()
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			} else if (drawType == 'triangle') {
				// 绘制三角形图片
				let type = triangle.type || 'isosceles'
				let coordinate = triangle.coordinate || []
				let direction = triangle.direction || 'top'
				if (type != 'custom') {
					this.setTriangleRotate(x, y, w, h, rotate, type)
				}
				this.drawTriangle({
					x,
					y,
					w,
					h,
					alpha,
					borderWidth,
					borderColor,
					color,
					coordinate,
					direction,
					drawType: type
				}, true)
				Context.clip()
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			}
			this.setAlpha(1)
			return resolve({
				success: true,
				data: img
			})
		})
	}

	/**
	 * 绘制矩形
	 * @param { Object } params 绘制内容
	 */
	drawRect(params = {}) {
		let { width, Context } = this
		let { x, y, w, h, r, color, alpha, isFill, lineWidth, 
			windowAlign, rotate, drawImage, borderColor, borderWidth, borderType, shadow, gradient } = this.getDrawParams(params, 'rect')
		if (r * 2 > h) {
			r = h / 2
		}
		if (!drawImage && rotate.deg) {
			Context.save()
			this.setRotate(x, y, w, h, rotate)
		}
		if (drawImage && shadow.show) {
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		if (!drawImage && shadow.show) {
			// Context.save()
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		if (windowAlign != 'none') {
			x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, w, windowAlign)
		}
		let tr = 0
		let tl = 0
		let br = 0
		let bl = 0
		if (typeof borderType == 'string') {
			switch(borderType) {
				case 'tr':
					tr = r
					break
				case 'tl':
					tl = r
					break
				case 'br':
					br = r
					break
				case 'bl':
					bl = r
					break
				default:
					tr = r
					tl = r
					br = r
					bl = r
			}
		}
		if (borderType instanceof Array) {
			if (borderType.includes('tr')) {
				tr = r
			}
			if (borderType.includes('tl')) {
				tl = r
			}
			if (borderType.includes('br')) {
				br = r
			}
			if (borderType.includes('bl')) {
				bl = r
			}
			if (borderType.includes('default')) {
				tr = r
				tl = r
				br = r
				bl = r
			}
		}
		// 上右 tr
		Context.lineTo(x + tl, y)
		Context.arc(x + w - tr, y + tr, tr, Math.PI * 1.5, 0, false)
		// 下右 br
		Context.lineTo(x + w, y + h - br)
		Context.arc(x + w - br,y + h - br, br, 0, Math.PI * .5, false)
		// 下左 bl
		Context.lineTo(x + bl, y + h)
		Context.arc(x + bl, y + h - bl, bl, Math.PI * .5, Math.PI, false)
		// 上左 tl
		Context.lineTo(x, y + tl)
		Context.arc(x + tl, y + tl, tl, Math.PI * 1, Math.PI * 1.5, false)
		Context.closePath()
		if (isFill) {
			if (borderWidth != 0) {
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			if (gradient.show) {
				let { type, relative, position, colors } = gradient
				color = this.getGradient(type || 'linear', relative, position, colors, { x, y })
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (!drawImage && rotate.deg) {
			Context.restore()
		}
		// if (!drawImage && shadow.show) {
		// 	// Context.restore()
		// }
		return new Promise(resolve => resolve(true))
	}

	/**
	 * 获取渐变
	 * @param { String } type 渐变类型 linear: 线性 circle: 圆形
	 * @param { Object } params 参数
	 * @returns 
	 */
	getGradient(type = 'linear', relative = true, position = {}, colors = [], box = {}) {
		let { x0, y0, x1, y1, x, y, r } = {
			x0: this.getCompany(position.x0) || 0,
			y0: this.getCompany(position.y0) || 0,
			x1: this.getCompany(position.x1) || 0,
			y1: this.getCompany(position.y1) || 0,
			x: this.getCompany(position.x) || 0,
			y: this.getCompany(position.y) || 0,
			r: this.getCompany(position.r) || 0,
		}
		if (type == 'linear') {
			position.x0 = relative ? x0 + box.x : x0
			position.y0 = relative ? y0 + box.y : y0
			position.x1 = relative ? x1 + box.x : x1
			position.y1 = relative ? y1 + box.y : y1
		} else {
			position.x = relative ? x + box.x : x
			position.y = relative ? y + box.y : y
			position.r = r
		}
		return type == 'linear' ?  this.getLinearGradient(position, colors) : this.getCircularGradient(position, colors)
	}

	/**
	 * 获取线性渐变颜色
	 * @param { Object } position 位置对象
	 * @param { Array } colors 颜色坐标
	 */
	getLinearGradient(position = {}, colors = []) {
		let { Context } = this
		let { x0, y0, x1, y1 } = position
		const grd = Context.createLinearGradient(x0, y0, x1, y1)
		for(let i of colors) {
			grd.addColorStop(i.stop, i.color)
		}
		return grd
	}

	/**
	 * 获取圆形渐变
	 * @param { Object } position 位置对象
	 * @param { Array } colors 颜色坐标
	 */
	getCircularGradient(position = {}, colors = []) {
		let { Context } = this
		let { x, y, r } = position
		const grd = Context.createCircularGradient(x, y, r)
		for(let i of colors) {
			grd.addColorStop(i.stop, i.color)
		}
		return grd
	}

	/**
	 * 绘制圆
	 * @param { Object } params 绘制内容
	 */
	drawArc(params = {}) {
		let { width, Context } = this
		let { x, y, r, s, e, d, alpha, isFill, lineWidth, color, 
			windowAlign, borderColor, borderWidth, 
			drawImage, shadow, gradient } = this.getDrawParams(params, 'arc')
		if (drawImage && shadow.show) {
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		if (!drawImage && shadow.show) {
			// Context.save()
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		x = x + r
		y = y + r
		if (windowAlign != 'none') {
			x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, r * 2, windowAlign)
			x += r
		}
		Context.arc(x, y, r, s, e, d)
		if (isFill) {
			if (borderWidth != 0) {
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			if (gradient.show) {
				let { type, relative, position, colors } = gradient
				color = this.getGradient(type || 'linear', relative, position, colors, { x, y })
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (!drawImage && shadow.show) {
			// console.log('进入')
			// Context.restore()
		}
	}


	/**
	 * 绘制三角形
	 * @param @param { Object } params 绘制内容
	 */
	drawTriangle(params = {}) {
		let { Context, width } = this
		let { x, y, w, h, color, alpha, isFill, lineWidth, drawType, 
			coordinate, rotate, windowAlign, direction, borderWidth, borderColor } = this.getDrawParams(params, 'triangle')
		if (windowAlign != 'none' && drawType != 'custom') {
			x = this.computedCenterX(width, w, windowAlign)
		}
		if (rotate.deg && drawType != 'custom') {
			Context.save()
			this.setTriangleRotate(x, y, w, h, rotate, drawType)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		if (drawType == 'isosceles') {
			switch (direction) {
				case 'top':
					Context.lineTo(x + w / 2, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					break
				case 'bottom':
					Context.lineTo(x, y)
					Context.lineTo(x + w, y)
					Context.lineTo(x + w / 2, y + h)
					break
				case 'right':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h / 2)
					break
				case 'left':
					Context.lineTo(x + w, y)
					Context.lineTo(x + w, y + h)
					Context.lineTo(x, y + h / 2)
					break
			}
		} else if (drawType == 'right') {
			switch (direction) {
				case 'top':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					break
				case 'bottom':
					Context.lineTo(x, y)
					Context.lineTo(x + w, y)
					Context.lineTo(x, y + h)
					break
				case 'left':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y)
					break
				case 'right':
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					Context.lineTo(x + w, y)
					break
			}
			
		} else if (drawType == 'custom') {
			for (let i of coordinate) {
				Context.lineTo(i[0], i[1])
			}
		}
		Context.closePath()
		if (isFill) {
			if (borderWidth != 0) {
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (rotate.deg && drawType != 'custom') {
			Context.restore()
		}
	}


	/**
	 * 绘制图片
	 * @param { Object } params 绘制内容
	 */
	drawImage(params = {}) {
		let { width, Context } = this
		return new Promise(async resolve => {
			try {
				let { x, y, w, h, r, src, alpha, drawType, borderWidth, windowAlign, color, mode, rotate, 
					triangle, isCompressImage, quality, borderColor, borderType, shadow,
					drawSrc, drawModeImage, drawImageInfo } = this.getDrawParams(params, 'image')
				if (!/\S/.test(src)) {
					return resolve({
						success: false,
						message: '图片路径为空'
					})
				}
				if (!TYPES.includes(this.type)) {
					// 不是2d需要先下载本地
					let srcRes = await this.getImageSrc(src)
					if (!srcRes.success) {
						return srcRes
					}
					src = srcRes.src
				}
				if (windowAlign != 'none') {
					x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, w, windowAlign)
				}
				// #ifndef H5
				// 压缩图片(不支持H5)
				// if (isCompressImage) {
				// 	let compressRes = await compressImage({
				// 		src,
				// 		quality
				// 	})
				// 	if (!compressRes.success) {
				// 		return resolve(compressRes)
				// 	}
				// 	src = compressRes.src
				// }
				// #endif
				// showLoading('获取图片信息中....')
				// console.log('src', src)
				let imageInfo = drawModeImage
				if (!imageInfo) {
					imageInfo = await getImageInfo(src)
					if (!imageInfo.success) {
						hideLoading()
						return resolve(imageInfo)
					}
				}
				const img = this.getImage(src)
				if (TYPES.includes(this.type)) {
					img.onload = async () => {
						return resolve(await this.drawImageByType({
							imageInfo, r, x, y, w, h, rotate,
							borderWidth, borderColor, color, alpha, borderType, triangle, 
							mode, drawType, img, shadow, drawSrc, drawModeImage
						}))
					}
				} else {
					return resolve(await this.drawImageByType({
						imageInfo, r, x, y, w, h, rotate,
						borderWidth, borderColor, color, alpha, borderType, triangle, 
						mode, drawType, img, shadow, drawSrc, drawModeImage
					}))
				}
			} catch(e) {
				return resolve({
					success: false,
					msg: '绘制图片出错' + e
				})
			}

		})
	}

	/**
	 * 高亮文字
	 * @param { Array } textArr 绘制文字数组
	 * @param { Array } highlightText 高亮文字
	 * @param { String } color 字体原颜色
	 * @param { String } font 字体
	 * @returns 
	 */
	getHighlightText(textArr, highlightText, color, font) {
		const highlightTextArr = []
		const highlightColorArr = []
		const { fontSize } = font
		highlightText.map(item => {
			const { text, color } = item
			return [...text].map(i => { 
				return {
					text: i,
					color
				}
			})
		}).forEach(item => {
			const texts = item.map(item => item.text)
			const colors = item.map(item => item.color)
			highlightTextArr.push(...texts)
			highlightColorArr.push(...colors)
		})
		let rowData = []
		textArr.forEach((item, index) => {
			const { x, y, w, text, tx, ty, tw } = item
			const texts = [...text]
			let position = []
			for (let i in texts) {
				const data = texts[i]
				const current = highlightTextArr.findIndex(i => data == i)
				if (current != -1) {
					// 符合规则的内容
					const ruleData = {
						text: data,
						index: i,
						x: x + countTextLength(this.Context, texts.join('').substring(0, i), fontSize),
						fontColor: highlightColorArr[current],
						y,
						tx,
						ty,
						tw
					}
					const beforeIndex = position.length == 0 ? 0 : Number(position[position.length - 1].index)
					const currentIndex = Number(ruleData.index)
					if (currentIndex - beforeIndex > 1) {
						const other = {
							text: texts.join('').substring(beforeIndex == 0 ? 0 : beforeIndex + 1, currentIndex),
							index: beforeIndex === 0 ? 0 : beforeIndex + 1,
							x: x + countTextLength(this.Context, texts.join('').substring(0, beforeIndex === 0 ? 0 : beforeIndex + 1), fontSize),
							fontColor: color,
							y,
							tx,
							ty,
							tw
						}
						rowData.push(other)
					}
					position.push(ruleData)
					rowData.push(ruleData)
				}
			}
			if (position.length === 0) {
				rowData.push({
					...item,
					tx,
					ty,
					tw,
					fontColor: color
				})
			}
			if (position.length != 0) {
				const lastIndex = Number(position[position.length - 1].index) + 1
				const length = texts.length
				if (lastIndex == length) return
				const other = {
					text: texts.join('').substring(lastIndex, length),
					index: lastIndex,
					x: x + countTextLength(this.Context, texts.join('').substring(0, lastIndex), fontSize),
					fontColor: color,
					y,
					tx,
					ty,
					tw
				}
				rowData.push(other)
			}
		})
		return rowData
	}

	/**
	 * 绘制文字
	 * @param { Object } params 绘制内容 
	 */
	async drawText(params = {}) {
		const { width, Context, company } = this
		let { x, y, w, h, text, textIndent,
			lastWidth, font, color, alpha, 
			isFill, line, windowAlign, textAlign, baseline, highlightText, textRect } = this.getDrawParams(params, 'text')
		Context.save()
		Context.beginPath()
		this.setAlpha(alpha)
		Context.font = font.style
		if (!TYPES.includes(this.type)) {
			Context.setTextBaseline(baseline)
		}else{
			Context.textBaseline = baseline
		}
		if (typeof text != 'string') {
			text += ''
		}
		let textArr = params.textArr
		if (!textArr) {
			textArr = this.computedFontTextLineHeight(x, y, w, text, textIndent, lastWidth, font, line, textAlign, windowAlign, color)
		}
		if (highlightText.length != 0) {
			textArr = this.getHighlightText(textArr, highlightText, color, font)
		}
		
		if (textRect.show) {
			// 水平的 垂直的
			let { vorizontal, vertical, ...textReactParmas } = textRect
			vertical = this.getCompany(vertical)
			vorizontal = this.getCompany(vorizontal)
			let tw = w == width ? this.getCompany(params.tw) : w
			tw = this.getCompany(company === 'rpx' ? this.pxToRpx(tw) : tw)
			let th = this.getCompany(h)
			let tx = textArr[0].x - vorizontal
			let ty = textArr[0].y - vertical
			// #ifdef MP-WEIXIN
			if (uni.getSystemInfoSync().platform === 'android') {
				ty += font.fontSize / 3
			}
			// #endif
			let ey = textArr[textArr.length - 1].ey + vertical
			th = ey - ty
			tw += (vorizontal * 2)
			// vertical = company === 'rpx' ? this.pxToRpx(vertical) : vertical
			// th += (vertical * 2)
			// Context.fillRect(tx, ty, tw, th)
			tx = company === 'rpx' ? this.pxToRpx(tx) : tx
			ty = company === 'rpx' ? this.pxToRpx(ty) : ty
			tw = company === 'rpx' ? this.pxToRpx(tw) : tw
			th = company === 'rpx' ? this.pxToRpx(th) : th
			await this.drawRect({
				x: tx,
				y: ty,
				w: tw,
				h: th,
				...textReactParmas
			})
		}
		if (isFill) {
			for (let i of textArr) {
				let { text, x, y, tx, ty, tw, fontColor } = i
				this.setFillStyle(fontColor)
				Context.fillText(text, x, y)
				if (line.lineStyle != 'none') {
					this.setFillStyle(color)
					this.drawLine({
						x: company == 'rpx' ? this.pxToRpx(tx) : tx,
						y: company == 'rpx' ? this.pxToRpx(ty) : ty,
						w: company == 'rpx' ? this.pxToRpx(tw) : tw,
						color,
						lineType: line.lineType,
						lineWidth: line.lineWidth
					}, true)
				}
			}
		} else {
			for (let i of textArr) {
				let { text, x, y, tx, ty, tw, fontColor } = i
				this.setStrokeStyle(fontColor)
				Context.strokeText(text, x, y)
				if (line.lineStyle != 'none') {
					this.setStrokeStyle(color)
					this.drawLine({
						x: company == 'rpx' ? this.pxToRpx(tx) : tx,
						y: company == 'rpx' ? this.pxToRpx(ty) : ty,
						w: company == 'rpx' ? this.pxToRpx(tw) : tw,
						color,
						lineType: line.lineType,
						lineWidth: line.lineWidth
					}, true)
				}
			}
		}
		Context.restore()
		this.setAlpha(1)
	}


	/**
	 * 获取字体样式
	 * @param { Object } font 字体
	 */
	getFont(font = {}) {
		let { fontSize, fontFamily, fontStyle, fontVariant, fontWeight, fontSizeBefore } = {
			fontSize: this.getCompany(font.size) || this.getCompany(24),
			fontSizeBefore: font.size || 12,
			fontFamily: font.family || 'sans-serif',
			// 斜体: italic, 倾斜体:oblique
			fontStyle: font.style || 'normal',
			fontVariant: font.variant || 'normal',
			// 粗体
			fontWeight: font.weight || 'normal'
		}
		return {
			fontSize, fontFamily, fontStyle, fontVariant, fontWeight, fontSizeBefore,
			style: `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize}px ${fontFamily}`
		}
	}

	/**
	 * 获取文字line样式
	 * @param { Object } line 行高
	 */
	getTextLine(line = {}) {
		return {
			// 显示的行数 -1 不限制
			lineNum: line.num || -1,
			// 行高
			lineHeight: this.getCompany(line.height) || 0,
			// none: 不需要 underline: 下划线, lineThrough 删除线
			lineStyle: line.style || 'none',
			// 线的类型 dashed 虚线 solid 实线
			lineType: line.type || 'solid',
			// 线宽度
			lineWidth: line.width || 1
		}
	}

	/**
	 * 画线
	 * @param { Object } params 绘制内容 
	 */
	drawLine(params = {}) {
		let { width, Context } = this
		let { x, y, color, w, algin, alpha, lineType, pattern, offset, lineCap, lineWidth, windowAlign } = {
			x: this.getCompany(params.x) || 0,
			y: this.getCompany(params.y) || 0,
			w: this.getCompany(params.w) || width - params.x,
			color: params.color || '#000000',
			algin: params.algin || 'right',
			alpha: params.alpha || 1,
			// dashed 虚线 solid 实线
			lineType: params.lineType || 'solid',
			// 详看CanvasContext.setLineDash文档
			// 一组描述交替绘制线段和间距（坐标空间单位）长度的数字
			pattern: params.pattern || [this.getCompany(6), this.getCompany(6)],
			// 虚线偏移量
			offset: this.getCompany(params.offset) || this.getCompany(6),
			lineWidth: params.lineWidth || this.getCompany(2),
			lineCap: params.lineCap || 'butt',
			// 窗口对齐的方式 默认: none 可选 居中: center 右边: right
			windowAlign: params.windowAlign || 'none'
		}
		Context.beginPath()
		this.setAlpha(alpha)
		if (lineType == 'dashed') {
			if (!TYPES.includes(this.type)) {
				Context.setLineDash(pattern, offset)
			} else {
				Context.setLineDash(pattern)
				Context.lineDashOffset = offset
			}
		}
		if (!TYPES.includes(this.type)) {
			Context.setLineCap(lineCap)
		} else {
			Context.lineCap = lineCap
		}
		this.setLineWidth(lineWidth)
		this.setStrokeStyle(color)
		switch (algin) {
			case 'right':
				if (windowAlign != 'none') {
					x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, w, windowAlign)
				}
				Context.moveTo(x, y)
				Context.lineTo(w + x, y)
				break
			case 'left':
				if (windowAlign != 'none') {
					x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, w, windowAlign)
				}
				Context.moveTo(x, y)
				Context.lineTo(windowAlign == 'none' ? x - w : x + w, y)
				break
			case 'top':
				Context.moveTo(x, y)
				Context.lineTo(x, -(y + w))
				break
			case 'bottom':
				Context.moveTo(x, y)
				Context.lineTo(x, y + w)
				break
		}
		Context.stroke()
		Context.closePath()
		if (!TYPES.includes(this.type)) {
			Context.setLineDash()
		} else {
			Context.setLineDash([0, 0])
			Context.lineDashOffset = 0
		}
		this.setAlpha(1)
	}

	/**
	 * 绘制二维码
	 * @param { Object } params 二维码参数
	 */
	drawQrCode(params = {}) {
		let { Context, width } = this
		return new Promise(async resolve => {
			let { x, y, image, windowAlign, ...options } = this.getDrawParams(params, 'qrcode')
			if (windowAlign != 'none') {
				x = this.computedCenterX(this.company == 'rpx' ? this.pxToRpx(width) : width, options.size, windowAlign)
			}
			//使用QRCodeAlg创建二维码结构
			let qrcodeAlgObjCache = []
			let qrCodeAlg = null
			let l = qrcodeAlgObjCache.length
			let d = 0
			for (let i = 0;i < l; i++) {
				d = i
				if (qrcodeAlgObjCache[i].text == options.text && qrcodeAlgObjCache[i].text.correctLevel == options.correctLevel) {
					qrCodeAlg = qrcodeAlgObjCache[i].obj
					break
				}
			}
			if (d == l) {
				qrCodeAlg = new QRCodeAlg(options.text, options.correctLevel)
				qrcodeAlgObjCache.push({
					text: options.text,
					correctLevel: options.correctLevel,
					obj: qrCodeAlg
				})
			}
			/**
			 * 计算矩阵点的前景色
			 * @param {Obj} config
			 * @param {Number} config.row 点x坐标
			 * @param {Number} config.col 点y坐标
			 * @param {Number} config.count 矩阵大小
			 * @param {Number} config.options 组件的options
			 * @return {String}
			 */
			let getForeGround = function (config) {
				let options = config.options
				if (options.pdground && (
					(config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
					(config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
					(config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
				)) {
					return options.pdground
				}
				return options.foreground
			}
			let count = qrCodeAlg.getModuleCount()
			let ratioSize = options.size
			let ratioImgSize = this.getCompany(image.size) || 30
			//计算每个点的长宽
			let tileW = (ratioSize / count).toPrecision(4)
			let tileH = (ratioSize / count).toPrecision(4)
			//绘制
			for (let row = 0; row < count; row++) {
				for (let col = 0; col < count; col++) {
					let w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW))
					let h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW))
					let foreground = getForeGround({
						row: row,
						col: col,
						count: count,
						options: options
					})
					this.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background)
					Context.fillRect(x + Math.round(col * tileW), y + Math.round(row * tileH), w, h)
				}
			}
			if (image.src) {
				let { src, r, color, borderWidth, borderColor } = image
				let dx = x + Number(((ratioSize - ratioImgSize) / 2).toFixed(2))
				let dy = y + Number(((ratioSize - ratioImgSize) / 2).toFixed(2))
				let drawImage = await this.drawImage({
					x: this.pxToRpx(dx),
					y: this.pxToRpx(dy),
					w: this.pxToRpx(ratioImgSize),
					h: this.pxToRpx(ratioImgSize),
					src,
					r,
					color,
					borderWidth,
					borderColor,
					drawType: 'rect',
					isCompressImage: false,
				}, true)
				if (!drawImage.success) {
					return resolve(drawImage)
				}
			}
			return resolve({
				success: true
			})
		})
	}

	/**
	 * 计算出文字一共有多少列,渲染位置之类
	 * @param { Number } x x轴
	 * @param { Number } y y轴
	 * @param { Number } w 文字宽度
	 * @param { String } text 文字内容
	 * @param { Number } textIndent 首行缩进
	 * @param { Number } lastWidth 最后一行的宽度 
	 * @param { Object } font 字体
	 * @param { Object } line 行高
	 * @param { String } textAlign 文字对齐方式
	 * @param { String } windowAlign 窗口对齐方式
	 * @returns 
	 */
	computedFontTextLineHeight(x, y, w, text, textIndent, lastWidth, font, line, textAlign, windowAlign, color) {
		let { Context, width } = this
		Context.font = font.style
		let { fontSize } = font
		let { lineNum, lineHeight, lineStyle } = line
		// 文字的总长度
		let textLength = countTextLength(Context, text, fontSize)
		if (w == 0 || w == this.getCompany(width)) {
			textLength > width ? w = width : w = textLength + fontSize
		}
		let rowData = []
		function getRowData(text) {
			let txt = ''
			let row = []
			let allData = []
			for (let i in text) {
				txt += text[i]
				let length = countTextLength(Context, txt, fontSize)
				if (textIndent != 0 && row.length === 0) {
					length += textIndent
				}
				if (length >= w - fontSize || i == text.length - 1) {
					let current = row.length == 0 ? 0 : row[row.length - 1].index
					let newAllData = Object.assign([], allData).splice(current, i)
					let limitLastText = lastWidth != 0 && newAllData.length != 0 && newAllData.reverse().find(item => item.length <= lastWidth)
					row.push({
						length,
						text: txt,
						index: i - 1,
						lastText: txt.substring(0, txt.length - 1) + '...',
						limitText: limitLastText ? limitLastText.text + '...' : '',
						limitTextWidth: countTextLength(Context, limitLastText.text + '...', fontSize),
					})
					txt = ''
				}
				allData.push({
					index: i,
					text: txt,
					length: length
				})
			}
			return row
		}
		if (text.includes('\n')) {
			let texts = text.split('\n')
			for (let text of texts) {
				rowData.push(...getRowData(text))
			}
		} else {
			rowData = getRowData(text)
		}
		// 行高
		lineHeight = lineHeight == 1 ? fontSize + 2 : lineHeight
		// 获取一共有多少列
		let lineSize = rowData.length
		// if (lineNum != - 1 && lineNum > lineSize) {
		// 	lineNum = lineSize
		// }
		let size = lineNum != -1 ? lineNum : lineSize
		if (size > lineSize) {
			size = lineSize
		}
		let textArr = []
		for (let i = 0; i < size; i++) {
			let { text, length: textLength, lastText, limitText, limitTextWidth } = rowData[i]
			let obj = {}
			let wx = x
			let tx = x
			if (i == 0 && textIndent != 0 && textAlign == 'none' && windowAlign == 'none') {
				textLength += textIndent
				wx += textIndent
				tx = wx
			}
			if (text && lineNum != -1 && i == lineNum - 1) {
				if (lastWidth > 0) {
					text = limitText
					textLength = limitTextWidth
				} else {
					text = textLength + fontSize >= w ? lastText : text
				}
			}
			if (textAlign != 'none' && textLength <= w) {
				let textW = w
				if (textLength == w) {
					textW = width
				}
				tx = this.computedCenterX(textW, textLength, textAlign)
				wx += tx
			}
			if (windowAlign != 'none' && textAlign != 'none') {
				wx = this.computedCenterX(width, w, windowAlign)
				wx += tx
				tx = wx
			} else if (windowAlign != 'none') {
				wx = this.computedCenterX(width, w, windowAlign)
				tx = wx
			}
			let tw = 0
			let ty = y + (i * lineHeight)
			if (lineStyle != 'none') {
				tx = tx + this.getCompany(4)
				tw = textLength + this.getCompany(4)
				if (lineStyle == 'underline') {
					ty =  y + (i * lineHeight) + fontSize
				}
				if (lineStyle == 'lineThrough') {
					ty = y + (i * lineHeight) + fontSize / 2
				}
			}
			obj.w = textLength
			obj.text = text
			obj.x = wx
			if (lineHeight == 0) {
				obj.y = y + (fontSize * i)
			} else {
				obj.y = y + (lineHeight * i)
			}
			obj.fontColor = color
			obj.lineColor = color
			obj.tw = tw
			obj.ty = ty
			obj.tx = tx
			obj.ey = obj.y + fontSize
			text && textArr.push(obj)
		}
		// console.log(textArr)
		return textArr
	}

	/**
	 * 计算内容需要显示在画布中间的x轴的位置
	 * @param { Number | String } boxWidth 容器的宽度
	 * @param { Number | String } contentWidth 内容宽度
	 * @param { String } type 类型 center: 水平 right: 右边
	 * @returns 
	 */
	computedCenterX(boxWidth, contentWidth, type = 'center') {
		if (type == 'center') {
			return (boxWidth - contentWidth) / 2
		}
		if (type == 'right') {
			return boxWidth - contentWidth
		}
	}

	/**
	 * 设置旋转角度
	 * @param { String } x x轴
	 * @param { String } y y轴
	 * @param { String } w 宽度
	 * @param { String } h 高度
	 * @param { Object } rotate 旋转内容
	 * @param { String } rotate.deg 旋转角度
	 * @param { String } rotate.type 类型 topLeft: 中心点在上左 topMiddle 中心点在上中 topRight 中心点在上右
	 *                             middleLeft: 中心点在中左 bottomMiddle 中心点在正中间 middleRight 中心点在中右
	 * 							   bottomLeft: 中心点在下左 bottomMiddle 中心点在下中 middleRight 中心点在下右
	 */
	setRotate(x, y, w, h, rotate) {
		let { Context } = this
		let deg = rotate.deg || 0
		let type = rotate.type || 'middle'
		let rx = x
		let ry = y
		switch (type) {
			case 'topLeft':
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'topMiddle':
				rx = x + (w / 2)
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'topRight':
				rx = x + w
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'bottomLeft':
				ry = y + h
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'bottomMiddle':
				rx = x + (w / 2)
				ry = y + h
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'bottomRight':
				rx = x + w
				ry = y + h
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'middleLeft':
				ry = y + (h / 2)
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'middleRight':
				rx = x + w
				ry = y + (h / 2)
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'middle':
				rx = x + (w / 2)
				ry = y + (h / 2)
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
		}
	}

	/**
	 * 设置三角形旋转角度
	 * @param { String } x x轴
	 * @param { String } y y轴
	 * @param { String } w 宽度
	 * @param { String } h 高度
	 * @param { Object } rotate 旋转内容
	 * @param { String } rotate.deg 旋转角度
	 * @param { String } rotate.type 类型 top: 上 left: 左 right: 右 middle: 中心
	 * @param { String } triangType 三角形类型(不支持自定义的三角形 ) right: 直角三角形 isosceles: 等腰三角形
	 */
	setTriangleRotate(x, y, w, h, rotate, triangType) {
		let { Context } = this
		let deg = rotate.deg || 0
		let type = rotate.type || 'top'
		let rx = x
		let ry = y
		switch (type) {
			case 'top':
				if (triangType == 'right') {
					rx = x
					ry = y
				} else {
					rx = x + w / 2
					ry = y
				}
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'left':
				rx = x
				ry = y + h
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'right':
				rx = x + w
				ry = y + h
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
			case 'middle':
				rx = x + w / 2
				ry = y + h / 2
				Context.translate(rx, ry)
				Context.rotate(deg * Math.PI / 180)
				Context.translate(-rx, -ry)
				break
		}
	}

	/**
	 * 排序drawArray 根据数据的zIndex进行排序，修改渲染顺序
	 * @param { Array } drawArray 绘制内容
	 */
	sortDrawArray(drawArray) {
		function compare() {
			return function(after, current) {
				let aZIndex = after.zIndex || 0
				let cZIndex = current.zIndex || 0
				return aZIndex - cZIndex
			}
		}
		drawArray.sort(compare())
		return drawArray
	}

	/**
	 * 往所有的回调信息里面添加内容
	 * @param { Object } params 内容
	 */
	async setAllCallBack(params) {
		let { width, Context } = this
		let { type, x, y, r, w, h, lineWidth, size, name, windowAlign, drawType, mode, src } = params
		w = w || width
		h = h || 0
		x = x || 0
		y = y || 0
		r = r || 0
		mode = mode || 'aspectFill'
		drawType = drawType || 'default'
		src = src || ''
		lineWidth = lineWidth || 1
		size = size || 0
		name = name || ''
		let sx = x
		let sy = y
		let ex = x + w
		let ey = y + h
		// 圆形
		if (type == 'arc') {
			ex = x + r * 2
			ey = y + r * 2
			w = r * 2
			h = r * 2
		}
		// 文字
		if (type == 'text') {
			let { company } = this
			let { text, textIndent, lastWidth, font, line, textAlign, windowAlign, color } = {
				text: String(params.text) || '',
				textIndent: this.getCompany(params.textIndent) || 0,
				lastWidth: params.lastWidth || 0,
				font: this.getFont(params.font),
				line: this.getTextLine(params.line),
				textAlign: params.textAlign || 'none',
				windowAlign: params.windowAlign || 'none',
				color: params.color || '#000000'
			}
			// if (w == this.getCompany(width)) {
			// 	w = 0
			// }
			let textArr = this.computedFontTextLineHeight(this.getCompany(x), this.getCompany(y), this.getCompany(w), text, textIndent, lastWidth, font, line, textAlign, windowAlign, color)
			let lastText = textArr[textArr.length - 1]
			let tx =  (lastText?.x || 0)
			let tw = (lastText?.w || 0)
			tx = company == 'rpx' ? this.pxToRpx(tx) : tx
			tw = company == 'rpx' ? this.pxToRpx(tw) : tw
			ex = tx + tw
			ey = lastText.ey
			ey = company == 'rpx' ? this.pxToRpx(ey) : ey
			params.textArr = textArr
			h = ey - sy
			// h = this.getCompany(textArr.length * font.fontSize)
			w = tw
			params.tx = tx
			params.tw = tw
			params.h = h
			// params.w = w
			// if (w == 0) {
			// 	w = countTextLength(Context, text, font.fontSize)
			// 	w = company == 'rpx' ? this.pxToRpx(w) : w
			// }
		}
		// 线
		if (type == 'line') {
			ey = y + lineWidth
			h = lineWidth
		}
		// 二维码
		if (type == 'qrcode') {
			ex = x + size
			ey = y + size
			w = size
			h = size
		}
		// 图片
		if (type == 'image') {
			windowAlign = windowAlign || 'none'
			if (windowAlign != 'none') {
				x = this.computedCenterX(width, this.getCompany(w), windowAlign)
			}
			let srcRes = await this.getImageSrc(src)
			if (!srcRes.success) {
				return srcRes
			}
			src = srcRes.src
			let imageInfo = await getImageInfo(src)
			if (!imageInfo.success) {
				hideLoading()
				return new Promise(resolve => resolve(false))
			}
			let modeImage = getModeImage(Number(imageInfo.width), Number(imageInfo.height), x, y, w, h, mode)
			let { dx, dy, dw, dh, sw, sh, sx, sy } = modeImage
			if (mode == 'widthFix') {
				h = sh
				ey = y + h
			}
			if (mode == 'heightFix') {
				w = sw
				ex = x + w
			}
			if (drawType == 'arc' && h == 0) {
				h = w
				ey = y + h
			}
			params.drawModeImage = modeImage
			params.drawSrc = src
			params.drawImageInfo = imageInfo
		}
		params.sx = sx
		params.sy = sy
		params.ex = ex
		params.ey = ey
		this.allCallBack.push({
			sx,
			sy,
			ex,
			ey,
			w,
			h,
			name,
			before: params.before || {}
		})
		return new Promise(resolve => resolve(true))
	}


	/**
	 * 获取当前绘制位置
	 * @returns 
	 */
	getDrawCurrentPosition() {
		let { allCallBack, callBack } = this
		return {
			...callBack.ctxObj,
			allCallBack,
		}
	}

	/**
	 * 修改canvas
	 * @param { Object } canvas canvas的新宽高
	 * @param { String } canvas.width canvas的新宽度 
	 * @param { String } canvas.height canvas的新高度
	 * @param { Object } background 背景的新宽高
	 * @param { String } background.w background的新宽度 
	 * @param { String } background.h background的新高度
	 */
	async updateCanvasStyle(canvas = {}, background = {}) {
		this.clearCanvas()
		this.width = this.getCompany(canvas.width || this.width)
		this.height = this.getCompany(canvas.height || this.height)
		this.background.w = background.w || this.background.w
		this.background.h = background.h || this.background.h
		// if (this.callBackData.updatecanvasback) {
		// 	this.callBackData.updatestyleback({
		// 		width: this.width + 'px',
		// 		height: this.height + 'px',
		// 	})
		// }
		this.isUpdate = true
		this.callBack = {
			bgObj: {
				width: this.background.w,
				height: this.background.h
			},
			ctxObj: {
				width: canvas.width,
				height: canvas.height
			},
			style: {
				width: this.width + 'px',
				height: this.height + 'px',
			}
		}
		// this.getContext()
		// this.createdSharePoster(this.drawArray)
	}

	/**
	 * 清空画布
	 */
	clearCanvas() {
		this.Context.clearRect(0, 0, this.callBack.ctxObj.width, this.callBack.ctxObj.height)
	}

	/**
	 * 绘制内容
	 * @returns 
	 */
	drawCanvas(drawArray) {
		let { Context, isUpdate } = this
		if (isUpdate) {
			this.allCallBack = []
		}
		return new Promise(async resolve => {
			try {
				for (let i of drawArray) {
					if (i.callBack && typeof i.callBack == 'function' && i.type != 'custom') {
						let beforeInfo = this.allCallBack.length == 0 ? {} : this.allCallBack[this.allCallBack.length - 1]
						let callBackInfo = i.callBack(beforeInfo, this.allCallBack) || {}
						let { callBack, ...data } = i
						i = { ...data, ...callBackInfo }
					}
					if (i.type != 'custom' && i.drawType != 'custom') {
						await this.setAllCallBack(i)
					}
					switch (i.type) {
						// 文字
						case 'text': 
							this.drawText(i)
							break
						// 矩形
						case 'rect':
							this.drawRect(i)
							break
						// 图片
						case 'image': 
							let image = await this.drawImage(i)
							if (!image.success) {
								return resolve(image)
							}
							break
						// 圆形
						case 'arc':
							this.drawArc(i)
							break
						// 三角形
						case 'triangle':
							this.drawTriangle(i)
							break
						// 线条
						case 'line':
							this.drawLine(i)
							break
						// 二维码
						case 'qrcode':
							await this.drawQrCode(i)
							break
						// 自定义
						case 'custom':
							i.setDarw(Context, this)
							break
					}
				}
				if (!isUpdate) {
					if (this.callBackData.endback) {
						if (this.callBackData.endback(this.getDrawCurrentPosition())) {
							await this.preDrawBackground()
							await this.drawCanvas(this.sortDrawArray(this.drawArray(this.callBack)))
							return
						}
					}
				}
				resolve({
					success: true
				})
			} catch(e) {
				hideLoading()
				return resolve({
					success: false,
					msg: '绘制内容失败:' + e
				})
			}
		})
	}

	/**
	 * 绘制背景
	 * @returns 
	 */
	drawBackground() {
		let { background, width, height, Context } = this
		return new Promise(async resolve => {
			let { type, ...params } = background
			Context.beginPath()
			Context.save()
			// 绘制背景色
			if (type == 'color') {
				this.drawRect({
					...params,
					w: params.w || width,
					h: params.h || height,
					color: params.color || '#ffffff'
				}, true)
			}
			// 绘制背景图
			if (type == 'image') {
				await this.drawImage({
					...params,
					w: params.w || width,
					h: params.h || height,
				}, true)
			}
			Context.clip()
			Context.restore()
			resolve({
				success: true
			})
		})
	}

	/**
	 * 创建canvas导出文件
	 * @returns 
	 */
	createdCanvasFilePath() {
		let { canvas, canvasId, width, height, _this, fileType, quality, type } = this
		if (type === '2d') {
			const dpr = uni.getSystemInfoSync().pixelRatio
			width = width * dpr
			height = height * dpr
		}
		return new Promise(resolve => {
			try {
				uni.canvasToTempFilePath({
					canvasId,
					canvas,
					x: 0,
					y: 0,
					width,
					height,
					quality,
					fileType,
					success: res => {
						return resolve({
							success: true,
							data: res.tempFilePath,
							msg: '绘画成功'
						})
					},
					fail: err => {
						hideLoading()
						return resolve({
							success: false,
							msg: `导出图片失败: ${JSON.stringify(err)}`
						})
					}
				}, _this || null)
			} catch (e) {
				hideLoading()
				return resolve({
					success: false,
					msg: '导出图片失败: 绘画错误' + e
				})
			}
		})
	}

	/**
	 * 预绘制背景
	 * @returns 
	 */
	preDrawBackground() {
		return new Promise(async resolve => {
			try {
				showLoading('初始化中...')
				// 绘制背景
				const drawBackground = await this.drawBackground()
				if (!drawBackground.success) {
					hideLoading()
					return resolve({
						success: false,
						msg: '初始化失败，绘制背景图失败'
					})
				}
				hideLoading()
				return resolve({
					success: true,
					msg: '初始化成功'
				})
			} catch(e) {
				hideLoading()
				resolve({
					success: false,
					msg: e
				})
			}
		})
	}

	/**
	 * 将绘制的内容绘制到画布上
	 * @param { Boolean } complete 是否完成，如果为true会绘制图片并返回图片路径
	 * @returns 
	 */
	canvasDraw(complete = true) {
		let { Context, drawDelayTime, type } = this
		return new Promise(async resolve => {
			setTimeout(async () => {
				hideLoading()
				if (TYPES.includes(type)) {
					if (complete) {
						return resolve(await this.exportImage())
					}
					return resolve({
						success: true,
						msg: '成功'
					})
				} else {
					await Context.draw(true, async () => {
						if (complete) {
							return resolve(await this.exportImage())
						}
						return resolve({
							success: true,
							msg: '成功'
						})
					})
				}
			}, drawDelayTime || 200)
		})
	}

	/**
	 * 预绘画
	 * @param { Function } drawArray 绘制内容 返回一个数组
	 * @param { Boolean } complete 是否完成，如果为true会绘制图片
	 * @returns 
	 */
	preDraw(drawArray, complete = false) {
		return new Promise(async resolve => {
			try {
				let { callBack, drawTipsText } = this
				showLoading(drawTipsText)
				let drawCanvas = await this.drawCanvas(this.sortDrawArray(drawArray(callBack)))
				// 绘制内容
				if (!drawCanvas.success) {
					hideLoading()
					return resolve(drawCanvas)
				}
				return resolve(await this.canvasDraw(complete))
			} catch(e) {
				hideLoading()
				resolve({
					success: false,
					msg: e
				})
			}

		})
	}

	/**
	 * 导出图片
	 * @returns 
	 */
	exportImage() {
		let { delayTime } = this
		return new Promise(resolve => {
			showLoading('导出图片中...')
			// 绘制图片
			setTimeout(async () => {
				resolve(await this.createdCanvasFilePath())
				hideLoading()
			}, delayTime || 200)
		})
	}

	/**
	 * 创建绘制海报
	 * @param { Function } drawArray 绘制内容 返回一个数组
	 * @returns 
	 */
	createdSharePoster(drawArray) {
		let { callBack, isUpdate } = this
		return new Promise(async resolve => {
			if (drawArray == null || drawArray == undefined) {
				return resolve({
					success: false,
					msg: '请传递绘制内容'
				})
			}
			let backgroundRes = await this.preDrawBackground()
			if (!backgroundRes.success) {
				return resolve(backgroundRes)
			}
			if (!isUpdate) {
				this.drawArray = drawArray
			}
			showLoading('绘制中...')
			let drawRes = await this.drawCanvas(this.sortDrawArray(this.drawArray(callBack)))
			// 绘制内容
			if (!drawRes.success) {
				hideLoading()
				return resolve(drawRes)
			}
			let res = await this.canvasDraw()
			if (isUpdate) {
				if (this.callBackData.updatecanvasback) {
					this.callBackData.updatecanvasback(res)
				}
				this.isUpdate = false
			}
			return resolve(res)
		})
	}
}